ホームに戻る
出典 :
方法: バインドされたデータを変換する - WPF .NET Framework | Microsoft Docs [C#/WPF] コンバーターの書き方 - Qiita WPF/UWP:ラジオボタンを双方向バインディングするには?[C#/VB]:.NET TIPS - @IT 【WPF】boolを任意のVisibilityプロパティにBindingする方法 | さんさめのC#ブログ
関連 :
データバインディング リソース マルチバインディング
目次 :

コンバーターとは

WPFのデータバインディングにおいて、ソースとターゲットとの間で形式(型や書式など)を変換する機構のこと。 例えば TextBox に DateTime 型をバインドし、そのうち年、月、日のみを表示するよう変換する、といったことが可能となる。

コンバーターの実装

コード

System.Windows.Data.IValueConverterインタフェースを実装する。実装が必要なメソッドは以下のふたつ。
Convert()
ソースからターゲットへの変換
ConvertBack()
ターゲットからソースへの変換
変換先のプロパティ( Convert() : ターゲット / ConvertBack() : ソース )を更新しない場合は、return DependencyProperty.UnsetValue;とする。
using System.Globalization; using System.Windows.Data; namespace _Converter; // コンバーター // DateTime ⇒ String [ValueConversion(typeof(DateTime), typeof(String))] public class DateConverter : IValueConverter { // ソース ⇒ ターゲット変換 public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { // 日付形式の文字列に変換して返す DateTime date = (DateTime)value; return date.ToShortDateString(); } // ターゲット ⇒ ソース変換 public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { // 日時に変換可能であれば変換して返す string strValue = value as string; DateTime resultDateTime; if (DateTime.TryParse(strValue, out resultDateTime)) { return resultDateTime; } // 変換できない場合は何もしない // (値を更新しない) return DependencyProperty.UnsetValue; } }

Convert() / ConvertBack() の詳細

引数及び戻り値は下表のとおり。
Convert() ConvertBack()
機能 ソース値をターゲット値に変換する
(ソース値からターゲット値を得る)
ターゲット値をソース値に変換する
(ターゲット値からソース値を得る)
戻り値 object (変換後の)ターゲット値 object (変換後の)ソース値
引数 object (変換前の)ソース値 object (変換前の)ターゲット値
Type 変換後(ターゲット値)の型 Type 変換後(ソース値)の型
object ConverterParameterとして渡されたパラメータ object ConverterParameterとして渡されたパラメータ
CultureInfo ConverterCultureとして渡されたカルチャ CultureInfo ConverterCultureとして渡されたカルチャ
ConverterParameterおよびConverterCultureはデータバインディングの構成時に指定する。 省略時はともに、既定値であるnullが格納される。いずれもConverterのメンバではなく、Bindingのメンバである点に注意。 ConverterCultureはロケールの情報を保持し、桁区切りや月日の並び順に影響する。多国籍対応を行う場合でなければ指定する必要は特に無い。

XAML

作成したコンバーターを親要素にリソースとして登録することで、デザインから参照することが可能となる。
このとき、コンバーターはStaticResourceとする必要がある(DynamicResourceはエラーとなる)。
<Window xmlns:conv="clr-namespace:_Converter"> : <!-- コードで作成したコンバータ―をリソースに登録 --> <!-- キー : dateConverter --> <Window.Resources> <conv:DateConverter x:Key="dateConverter"/> </Window.Resources> : <!-- コンバーター(キー : dateConverter )を適用 --> <!-- StaticResource として参照 --> <TextBlock Name="StartDateDTKey" Grid.Row="2" Grid.Column="1" Text="{Binding Path=StartDate, Converter={StaticResource dateConverter}}" Style="{StaticResource textStyleTextBlock}"/> : </Window>

応用#1 : ラジオボタンを双方向バインディングする

画像
チェックされたラジオボタンに対応する列挙値(Enum)を取得したい場合、以下のように実装する。
PropertyChanged 、Reactive の実装は省略。
コード : コンバーターの定義
using System.Globalization; using System.Windows.Data; namespace _Converter // 列挙体の定義 public enum mode { Simple, Detail } // Enum ⇒ Bool 変換用コンバーター public class EnumToBoolConverter : IValueConverter { // ソース ⇒ ターゲット変換 public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var paramStr = parameter as string; // 比較値が null または // ソース値が定義域に含まれない場合は値を更新しない if ( paramStr is null || !Enum.IsDefined(targetType, value) ) { return DependencyProperty.UnsetValue; } // ソース値が比較値に一致すれば true 、 // そうでなければ false を返す return Enum.Parse( value.GetType(), paramStr ).Equals(value); } // ターゲット ⇒ ソース変換 public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { var paramStr = parameter as string; // 比較値が null または // ターゲット値が true でない場合は値を更新しない if( paramStr is null || !true.Equals( value ) ) { return DependencyProperty.UnsetValue; } return Enum.Parse( targetType, paramStr ); } }
XAML : ラジオボタンの配置、コンバーターの適用
<Window xmlns:res="clr-namespace:_Converter"> : <StackPanel> <StackPanel.Resources> <!-- コンバーター EtoB 宣言 --> <res:EnumToBoolConverter x:Key="EtoB" /> </StackPanel.Resources> <!-- RadioButton --> <!-- ターゲット : IsChecked (bool) --> <!-- ソース : ModeValue (mode) --> <!-- コンバーター : EtoB --> <!-- 「簡易」- ConverterParameter = Simple ( mode.Simple ) --> <RadioButton Content="簡易" IsChecked="{Binding ModeValue, Converter={StaticResource EtoB}, Mode=TwoWay, ConverterParameter=Simple}" /> <!-- 「詳細」- ConverterParameter = Detail ( mode.Detail ) --> <RadioButton Content="詳細" IsChecked="{Binding ModeValue, Converter={StaticResource EtoB}, Mode=TwoWay, ConverterParameter=Detail}" /> : </StackPanel> : </Window>

解説

画像 ソース値を変更するとConvert()が呼ばれ、ソース値がvalueに、ConverterParameter( mode.Simple または mode.Detail )がparameterに渡される。 parameterを比較値として用い、valueparameterに一致する場合にConvert()trueを返すため、対応するラジオボタンがチェックされる。 逆にチェック状態を変更するとConvertBack()が呼ばれ、ConverterParameterで指定された列挙子がソースに反映される。 注意が必要な点として、ラジオボタンのチェック状態を変更すると「チェックされた」ラジオボタンと、「チェックを外された」ラジオボタンの双方でCheckedChangedイベントが発生するため、 ConvertBack()もそれぞれで(計2回)コールされる。 ソースに反映するのはチェックされたラジオボタンであるため、valuetrue(チェックされている)の場合のみソース値の変更を行う。

応用#2 : bool を指定した Visibility にバインドする

コントロールの可視性(Visibility)をbool値によって切り替えられるコンバーターの例を示す。 ソースがtrueの場合はCollapsedfalseの場合はVisibleを返すよう、TrueToFalseToプロパティをリソース宣言時に指定している。 ここではTrueToFalseToにデフォルト値を割り当てていないため、true/falseに対応する値を用途に応じて切り替えることが可能であるが、 毎回指定する必要がある。
コード : コンバーターの定義
using System.Globalization; using System.Windows.Data; namespace _Converter; public class BoolToAnyVisibilityConverter : IValueConverter { public Visibility? TrueTo { get; set; } //< ソースが true の場合に返す値 public Visibility? FalseTo { get; set; } //< ソースが false の場合に返す値 // ソース ⇒ ターゲット変換 public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { // TrueTo が設定されていない場合は例外 if (!TrueTo.HasValue) { throw new InvalidOperationException($"{nameof(TrueTo)}にVisibilityが設定されていません"); } // FalseTo が設定されていない場合は例外 if (!FalseTo.HasValue) { throw new InvalidOperationException($"{nameof(FalseTo)}にVisibilityが設定されていません"); } // ソースが bool でない場合は値を更新しない if (!(value is bool b)) { return DependencyProperty.UnsetValue; } // ソース(bool)が true の場合は TrueTo 、false の場合は FalseTo を返す return b ? TrueTo : FalseTo; } // ターゲット ⇒ ソース変換 : 何もしない public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
XAML : コンバーターの適用
ここでTrueToFalseToに値を設定する。
<Window xmlns:res="clr-namespace:_Converter"> : <StackPanel> <StackPanel.Resources> <!-- コンバーター宣言 --> <!-- TrueTo に Collapsed 、FalseTo に Visible を設定 --> <res:BoolToAnyVisibilityConverter x:Key="BoolToCollapse" TrueTo="Collapsed" FalseTo="Visible"/> </StackPanel.Resources> : </StackPanel> : </Window>